package com.xu.cloud.common.jpa;

import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.repository.query.EscapeCharacter;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.querydsl.EntityPathResolver;
import org.springframework.data.querydsl.SimpleEntityPathResolver;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import org.springframework.data.repository.core.support.TransactionalRepositoryFactoryBeanSupport;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

/**
 * JpaRepositoryFactoryBeanV2
 *
 * @author xuguan
 * @since 2025/6/10
 */
public class JpaRepositoryFactoryBeanV2<T extends Repository<S, ID>, S, ID> extends TransactionalRepositoryFactoryBeanSupport<T, S, ID> {
    @Nullable
    private EntityManager entityManager;
    private EntityPathResolver entityPathResolver;
    private EscapeCharacter escapeCharacter;

    protected JpaRepositoryFactoryBeanV2(Class<? extends T> repositoryInterface) {
        super(repositoryInterface);
        this.escapeCharacter = EscapeCharacter.DEFAULT;
    }

    @PersistenceContext
    public void setEntityManager(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    public void setMappingContext(MappingContext<?, ?> mappingContext) {
        super.setMappingContext(mappingContext);
    }

    @Autowired
    public void setEntityPathResolver(ObjectProvider<EntityPathResolver> resolver) {
        this.entityPathResolver = (EntityPathResolver) resolver.getIfAvailable(() -> {
            return SimpleEntityPathResolver.INSTANCE;
        });
    }

    protected RepositoryFactorySupport doCreateRepositoryFactory() {
        Assert.state(this.entityManager != null, "EntityManager must not be null!");
        return this.createRepositoryFactory(this.entityManager);
    }

    protected RepositoryFactorySupport createRepositoryFactory(EntityManager entityManager) {
        JpaRepositoryFactoryV2 jpaRepositoryFactory = new JpaRepositoryFactoryV2(entityManager);
        jpaRepositoryFactory.setEntityPathResolver(this.entityPathResolver);
        jpaRepositoryFactory.setEscapeCharacter(this.escapeCharacter);
        return jpaRepositoryFactory;
    }

    public void afterPropertiesSet() {
        Assert.state(this.entityManager != null, "EntityManager must not be null!");
        super.afterPropertiesSet();
    }

    public void setEscapeCharacter(char escapeCharacter) {
        this.escapeCharacter = EscapeCharacter.of(escapeCharacter);
    }
}